package com.ming.common.liteflow.core.el;

import com.ming.common.util.CommonUtil;
import com.ming.common.liteflow.core.dynamic.IvyDynamicClass;
import com.ming.common.liteflow.core.exec.ELExecUtil;
import com.ming.common.liteflow.core.graph.GraphEL;
import com.ming.common.liteflow.core.graph.LogicFlowData;
import com.ming.common.liteflow.core.graph.Node;
import com.ming.common.liteflow.core.json.ELJsonUtil;
import com.ming.common.liteflow.core.node.IvyCmp;
import com.ming.common.liteflow.core.execption.LiteFlowELException;
import com.yomahub.liteflow.builder.el.ELBus;
import com.yomahub.liteflow.builder.el.ELWrapper;
import com.yomahub.liteflow.builder.el.WhenELWrapper;
import com.yomahub.liteflow.core.FlowExecutor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Flow {

    private List<GraphEL> graphELList;
    private boolean formatEL = false;
    private ELWrapper wrapper;
    private Map<Long,IvyCmp> nodeInfoMap;
    private List<IvyCmp> nodeInfoList;
    private List<IvyDynamicClass> dynamicClassList;
    private FlowExecutor flowExecutor;

//    public static Flow NEW(){
//        return new Flow();
//    }

    public Flow nodeInfoList(List<IvyCmp> list) {
        this.nodeInfoList = list;
        this.nodeInfoMap = list.stream().collect(Collectors.toMap(IvyCmp::getId, m->m));
        return this;
    }
    public Flow dynamicClassList(List<IvyDynamicClass> list) {
        this.dynamicClassList = list;
        return this;
    }

    public Flow logicFlow(String json) throws LiteFlowELException {
        graphELList = new ArrayList<>();
        List<LogicFlowData> flowDataList = ELJsonUtil.getLogicFlowGroup(json);
        if(flowDataList.size() > 1){
            //多起点嵌套处理
            WhenELWrapper when = ELBus.when();
            for (LogicFlowData data : flowDataList){
                GraphEL graphEL = GraphEL.getGraphEL(data,nodeInfoMap);
                when.when(FlowConvertEL.logicFlow(graphEL));
                graphEL.setGroupNodeProp(graphEL.getStartNode(), when);//设置分组属性
                graphELList.add(graphEL);
            }
            this.wrapper = when;
        }else if(flowDataList.size() == 1){
            //单起点嵌套处理
            GraphEL graphEL = GraphEL.getGraphEL(flowDataList.get(0),nodeInfoMap);
            this.wrapper = FlowConvertEL.logicFlow(graphEL);
            graphELList.add(graphEL);
        }
        return this;
    }

    public Flow formatEL(){
        this.formatEL = true;
        return this;
    }

    public String buildEL(){
        return wrapper.toEL(formatEL);
    }

    public String buildEL(boolean formatEL){
        if(wrapper != null){
            return wrapper.toEL(formatEL);
        }
        return null;
    }

    public Flow flowExecutor(FlowExecutor flowExecutor){
        this.flowExecutor = flowExecutor;
        return this;
    }

    public List<Node> flowNodeList(){
        List<Node> flowNodeList = new ArrayList<>();
        for (GraphEL graphEL : graphELList){
            List<Node> list = graphEL.getList().keySet().stream().collect(Collectors.toList());
            flowNodeList.addAll(list);
        }
        return flowNodeList;
    }

    public List<Node> fallbackList(){
        List<Node> fallbackList = new ArrayList<>();
        for (GraphEL graphEL : graphELList){
            List<Node> list = graphEL.getList().keySet().stream().collect(Collectors.toList());
            if(CommonUtil.collUtil.isNotEmpty(graphEL.getFallbackList())){
                fallbackList.addAll(graphEL.getFallbackList());
            }
        }
        return fallbackList;
    }

    public String exec(){
        if(graphELList.size() == 1){
            GraphEL graphEL = graphELList.get(0);
            List<Node> flowNodeList = graphEL.getList().keySet().stream().collect(Collectors.toList());
            return ELExecUtil.exec(flowExecutor, nodeInfoList,dynamicClassList, flowNodeList, graphEL.getFallbackList(), wrapper.toEL());
        }
        List<Node> flowNodeList = new ArrayList<>();
        List<Node> fallbackList = new ArrayList<>();
        for (GraphEL graphEL : graphELList){
            List<Node> list = graphEL.getList().keySet().stream().collect(Collectors.toList());
            flowNodeList.addAll(list);
            if(CommonUtil.collUtil.isNotEmpty(graphEL.getFallbackList())){
                fallbackList.addAll(graphEL.getFallbackList());
            }
        }
        return ELExecUtil.exec(flowExecutor, nodeInfoList,dynamicClassList, flowNodeList, fallbackList, wrapper.toEL());
    }

}
